<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Ali\Api;
use App\Http\Controllers\Ali\DysmsController;
use App\Http\Controllers\Controller;
use DB;
use Illuminate\Support\Facades\Schema;
use Log;

//工器具到期
class SampleInfoExpireController extends Controller
{
    private $noticeData=[];
    private $set;
    private $sendDate;
    private $groupId;
    private $failCount = 0;
    private $decedCount = 0;

    /*每天10:00发送即将到期短信*/
    public function handle() {
        set_time_limit(0);
        ini_set('max_execution_time', 0);
        ini_set('memory_limit', '-1');
        $urls = DB::table('sample_info_exipre_notice_url')->pluck('url');
        $aliKey = config('constant.alidysms_key');
        $aliSec = config('constant.alidysms_secret');
        foreach($urls as $url) {
            $curl = 'http://'.$url.'/api/sampleinfo/expire/sms?_key='.$aliKey.'&_secret='.$aliSec;
            Log::info(date('Y-m-d H:i:s').'短信发送:'.$curl);
            curl($curl);
        }
    }

    /*晚上0:30分检查发送中的短信是否发送成功*/
    public function checkSms() {
        set_time_limit(0);
        ini_set('max_execution_time', 0);
        ini_set('memory_limit', '-1');
        $app_names = get_databases();
        $sms = new DysmsController();
        foreach($app_names as $appName) {
            if(Schema::connection("mysql_{$appName}")->hasTable('a_sms_log')){
                $set = DB::connection("mysql_{$appName}")->table('setting_sys')->where('key', 'sms')->value('value');
                $set = json_decode($set, true);
                //同步短信条数
                $total = DB::connection("mysql_{$appName}")->table('a_sms_buy')->where('audit',2)->sum('sms_num');
                $sented = DB::connection("mysql_{$appName}")->table('a_sms_log')->where('status','!=',2)->orWhere('status',4)->count();
                $left = $total - $sented;
                if($set['count'] > $left) {
                    $set['count'] = $left;
                    DB::connection("mysql_{$appName}")->table('setting_sys')->where(['key' => 'sms'])->update(['value' => json_encode($set)]);
                }

                $data = DB::connection("mysql_{$appName}")->table('a_sms_log')->where('status', 1)->get();
                if(count($data) === 0) {
                    continue;
                }

                $failSmsCount = 0;
                $failIds = $sucesIds = [];
                foreach($data as $item) {
                    $date = substr(str_replace('-', '', $item->ctime), 0, 8);
                    $params = ['CurrentPage' => 1, 'PageSize' => 10, 'PhoneNumber' => $item->mobile, 'SendDate' => $date, 'BizId' => $item->BizId];     //手机号默认空，在循环中添加
                    $res1 = $sms->QuerySendDetails($params);
                    Log::info('短信查询结果：'.$res1);
                    //修改返回值
                    $res = json_decode($res1);
                    if($res->Code === 'OK' && $res->Message === 'OK') {
                        if(isset($res->SmsSendDetailDTOs->SmsSendDetailDTO)) {
                            $detail = $res->SmsSendDetailDTOs->SmsSendDetailDTO;
                            foreach($detail as $index => $value) {
                                switch($value->SendStatus) {
                                    case 2:
                                        $failSmsCount += 1;
                                        $failIds[] = $item->id;
                                        break;
                                    case 3:
                                        $sucesIds[] = $item->id;
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                    }
                }
                DB::beginTransaction();
                try {
                    //增加短信数量
                    $set['count'] += $failSmsCount;
                    DB::connection("mysql_{$appName}")->table('setting_sys')->where(['key' => 'sms'])->update(['value' => json_encode($set)]);
                    //修改短信发送状态
                    DB::connection("mysql_{$appName}")->table('a_sms_log')->whereIn('id', $failIds)->update(['status' => 2]);
                    DB::connection("mysql_{$appName}")->table('a_sms_log')->whereIn('id', $sucesIds)->update(['status' => 3]);
                    DB::connection("mysql_{$appName}")->commit();
                } catch(\Exception $e) {
                    DB::connection("mysql_{$appName}")->rollBack();
                    Log::info($e->getMessage());
                }
            }
        }
    }

    /*发短信，写日志*/
    public function sms() {
        set_time_limit(0);
        ini_set('max_execution_time', 0);
        ini_set('memory_limit', '-1');
        $this->sendDate = date('Y-m-d');
        $set = DB::table('setting_sys')->where('key', 'sms')->value('value');
        $set = json_decode($set, true);
        if(!$set) {
            return Log::info('未进行短信设置');
        }
        if($set['is_open'] !== 'on') {
            return Log::info('未开启短信提醒');
        }
        if($set['gqj_notice_early_days'] == 0 || $set['gqj_notice_loop_days'] == 0) {
            return Log::info('未设置提前提醒天数或循环提醒天数');
        }
        if($set['count'] < 0) {
            //DB::table('a_sms_log')->insert(['content' => '没有短信可用了', 'ErrCode' => '没有短信可用了', 'status' => 2]);
            return Log::info('没有短信可用了！');
        }
        $this->set = $set;
        $noticeDate = $this->getNoticeDate($set);
        $this->noticeData[0] = $noticeDate;
        $special = DB::table('a_sms_gqj_set as a')->leftJoin('a_std_tool_rel as b','a.std_tool_rel_id','=','b.id')->select('a.*','b.tool_id')->get()->KeyBy('tool_id')->toArray();
        $dataTemp = [];
        $today = $this->sendDate;
        foreach($special as $item){
            $specialSet = [
               'gqj_notice_early_days'=>$item->early_days,
               'gqj_notice_loop_days'=>$item->loop_days,
               'gqj_notice_delay_days'=>$item->delay_days,
            ];
            $specialNoticeDate = $this->getNoticeDate($specialSet);
            $this->noticeData[$item->tool_id] = $specialNoticeDate;
            $dataTemp[] = DB::table('a_sample_info as a')
                        ->leftJoin('a_contract as b', 'a.contract_id', '=', 'b.id')
                        ->leftJoin('a_contract_gaiyao as c', 'a.contract_gaiyao_id', '=', 'c.id')
                        ->where([['a.res', '=', 1], ['a.notice', '=', 1]])
                        ->where(function($query) use ($today) {
                            $query->whereNull('a.notice_last_date')->orWhere('a.notice_last_date', '<', $today);
                        })
                        ->where('c.tool_id', $item->tool_id)
                        ->whereIn('a.next_time', $specialNoticeDate)
                        ->select('b.client_name', DB::raw('Count( res = 1 OR NULL ) AS total,any_value(client_tel) as client_tel'))
                        ->groupBy('b.client_name')
                        ->get()->toArray();
        }
        $specialIds = array_keys($special);
        $dataTemp[] = DB::table('a_sample_info as a')
                  ->leftJoin('a_contract as b', 'a.contract_id', '=', 'b.id')
                  ->leftJoin('a_contract_gaiyao as c', 'a.contract_gaiyao_id', '=', 'c.id')
                  ->where([['a.res', '=', 1], ['a.notice', '=', 1]])
                  ->where(function($query) use ($today) {
                      $query->whereNull('a.notice_last_date')->orWhere('a.notice_last_date', '<', $today);
                  })
                  ->whereNotIn('c.tool_id', $specialIds)
                  ->whereIn('a.next_time', $noticeDate)
                  ->select('b.client_name', DB::raw('Count( res = 1 OR NULL ) AS total,any_value(client_tel) as client_tel'))
                  ->groupBy('b.client_name')
                  ->get()->toArray();
        $data = [];
        foreach($dataTemp as $item){
            foreach($item as $value){
                $data[] = $value;
            }
        }
        //			$data = [];
        //			array_push($data, json_decode(json_encode(['client_name' => '保定汇邦检测有限责任公司', 'total' => 10, 'client_tel' => '15910683901'])));

        //为了防止同时发送相同手机号引起的错误，进行分组处理
        $dataAry = $this->deviceData($data);
        foreach($dataAry as $data) {
            $this->SendBatchSms($data);
        }
        //修正短信数量（多退少补）
        $this->upSmsCount();
    }

    private function getNoticeDate($set){
        $early = $set['gqj_notice_early_days'];
        $loop = $set['gqj_notice_loop_days'];
        $delay = $set['gqj_notice_delay_days'];
        $noticeDate = [];
        for($i = $early; $i >= -$delay; $i -= $loop) {
            $noticeDate[] = date('Y-m-d', strtotime('+'.$i.' days'));
        }
        return $noticeDate;
    }

    //为了防止同时发送相同手机号引起的错误，进行分组处理
    private function deviceData($data) {
        $dataAry = []; //三维数组
        foreach($data as $index => $item) {
            if(strlen($item->client_tel) < 11) {
                continue;
            }
            if(empty($dataAry)) {
                $dataAry[$index][] = $item;
                continue;
            }
            $none = true;
            foreach($dataAry as $key1 => $value1) {
                $value1 = (array)$value1;
                $tels = array_column($value1, 'client_tel');
                if(!in_array($item->client_tel, $tels)) {
                    $none = false;
                    array_push($dataAry[$key1], $item);
                    break;
                }
                else {
                    continue;
                }
            }
            if($none) {
                $dataAry[$index][] = $item;
            }
        }
        return $dataAry;
    }

    private function befSms($Param) {
        DB::beginTransaction();
        try {
            //减少短信数量
            $this->decedCount = count($Param['PhoneNumbers']);
            $this->set['count'] -= $this->decedCount;
            DB::table('setting_sys')->where(['key' => 'sms'])->update(['value' => json_encode($this->set)]);

            //写日志
            $this->groupId = 'aly_'.uniqid().rand(1000, 9999);   //aly_ : 阿里云_
            $data = [];
            foreach($Param['PhoneNumbers'] as $k => $phoneNumber) {
                $name = $Param['TemplateParams'][$k]['name'];
                $num = $Param['TemplateParams'][$k]['num'];
                $data[] = [
                    'mobile'      => $phoneNumber,
                    'content'     => $Param['TemplateCode'] === 'SMS_218160860' ? '尊敬的'.$name.'，您有'.$num.'件工器具的合格证即将到期，请及时进行复检！' : '',
                    'client_name' => $name,
                    'BizId'       => $this->groupId,
                    'param'       => json_encode($Param['TemplateParams'][$k])
                ];
            }
            DB::table('a_sms_log')->insert($data);
            DB::commit();
        } catch(\Exception $e) {
            DB::rollBack();
            Log::info($e->getMessage());
            return false;
        }
        return true;
    }

    //短信签名
    private function getSmsSignName() {
        //    try {
        //        $sign_name = DB::table('a_sms_sign')->where('is_def', 1)->value('name');
        //    } catch (\Exception $E) {
        //        $sign_name = '汇邦检测';
        //    }
        $sign_name = config('constant.alidysms_sign') ? config('constant.alidysms_sign') : '汇邦检测';
        return $sign_name;
    }

    //短信提醒
    private function SendBatchSms($data) {
        $PhoneNumbers = $SignName = $TemplateParam = [];
        $sign_name = $this->getSmsSignName();
        foreach($data as $item) {
            $phone = substr(trim($item->client_tel), 0, 11);
            if(strlen($phone) === 11) {
                array_push($PhoneNumbers, $item->client_tel);
            }
            array_push($SignName, $sign_name);
            array_push($TemplateParam, ['name' => $item->client_name, 'num' => $item->total]);
        }
        if(count($PhoneNumbers) > $this->set['count']) {
            Log::info('短信条数不足');
            return '短信条数不足';
        }

        $Param = [
            'PhoneNumbers'   => $PhoneNumbers,
            'SignNames'      => $SignName,
            'TemplateParams' => $TemplateParam,
            'TemplateCode'   => 'SMS_218160860'
        ];
        //			$Param = ['PhoneNumbers' => $PhoneNumbers, 'SignNames' => $SignName, 'TemplateParams' => $TemplateParam, 'TemplateCode' => 'SMS_218174966'];
        //先修改数据：减少短信数量+写日志
        $befSms = $this->befSms($Param);
        if(!$befSms) {
            return false;
        }
        //发短信
        $sms = new DysmsController();
        $rest = $sms->SendBatchSms($Param);
        Log::info($rest);
        $rest = json_decode($rest);
        $Param['res'] = $rest;
        //校验短信
        if($rest->Code === 'OK' && $rest->Message === 'OK') {
            date_default_timezone_set('PRC');
            //修改发送回执ID
            DB::table('a_sms_log')->where('BizId', $this->groupId)->update(['BizId' => $Param['res']->BizId,'send_date'=>date('Y-m-d H:i:s')]);
            sleep(20*count($PhoneNumbers));   //为防止数据查询不到，这里过20*发送数量 秒再查询状态
            $this->getDetail($sms, $Param);
        }
        else {
            $this->failEdit($Param);
        }
    }

    //群发发送失败！
    private function failEdit($Param) {
        //增加短信条数
        DB::beginTransaction();
        try {
            //恢复短信数量
            $this->set['count'] += $this->decedCount;
            DB::table('setting_sys')->where(['key' => 'sms'])->update(['value' => json_encode($this->set)]);
            DB::table('a_sms_log')->where('BizId', $this->groupId)->update(['status' => 2, 'ErrCode' => $Param['res']->Code, 'back' => json_encode($Param['res']),'send_date'=>date('Y-m-d H:i:s')]);
            DB::commit();
        } catch(\Exception $e) {
            DB::rollBack();
            Log::info('短信发送失败返回：'.$e->getMessage());
            return false;
        }
        return true;
    }


    private function getDetail($sms, $Param) {
        $date = str_replace('-', '', $this->sendDate);
        $bizid = $Param['res']->BizId;
        $params = ['CurrentPage' => 1, 'PageSize' => 10, 'PhoneNumber' => '', 'SendDate' => $date, 'BizId' => $bizid];     //手机号默认空，在循环中添加
        $data = [];
        foreach($Param['PhoneNumbers'] as $k => $phoneNumber) {
            $params['PhoneNumber'] = $phoneNumber;
            $res1 = $sms->QuerySendDetails($params);
            Log::info('短信查询结果：'.$res1);
            //修改返回值
            $res = json_decode($res1);
            if($res->Code === 'OK' && $res->Message === 'OK') {
                $TotalCount = $res->TotalCount;
                if(isset($res->SmsSendDetailDTOs->SmsSendDetailDTO)) {
                    $detail = $res->SmsSendDetailDTOs->SmsSendDetailDTO;
                    $statusAry = [];
                    foreach($detail as $index => $item) {
                        $data[$item->SendStatus][] = $Param['TemplateParams'][$k]['name'];
                        array_push($statusAry, intval($item->SendStatus));
                    }

                    $ary = array_count_values($statusAry);
//                    $s1 = intval(isset($ary[1]) ? $ary[1] : 0);
                    $s2 = intval(isset($ary[2]) ? $ary[2] : 0);
                    $s3 = intval(isset($ary[3]) ? $ary[3] : 0);
                    $status = 1;  //默认发送中
                    if($s3 == $TotalCount) {
                        $status = 3;
                    }
                    else {
                        if($s3 > 0 && $s2 > 0) {
                            $status = 4;
                        }
                        if($s2 == $TotalCount) {
                            $status = 2;
                        }
//                        if($s1 > 0) {
//                            $detail['sendingCount'] = $s1;
//                        }
                    }
                    //增加失败的短信条数
                    $this->failCount += $s2;
                    // 修改日志
                    DB::table('a_sms_log')->where('BizId', $bizid)->where('mobile', $phoneNumber)->update(['status' => $status, 'back' => json_encode($res)]);
                }
            }
        }
        $this->upSampleInfo($data);
    }


    private function upSmsCount() {
        //增加短信数量
        $this->set['count'] += $this->failCount;
        DB::table('setting_sys')->where(['key' => 'sms'])->update(['value' => json_encode($this->set)]);
    }

    //修改最近一次提醒时间
    private function upSampleInfo($data) {
        foreach($data as $status => $client_names) {
            //发送成功
            if($status == 3) {
                $date = $this->sendDate;
                //修改最近一次提醒时间
                foreach($this->noticeData as $k=>$noticeDate){
                    if($k==0){
                        DB::table('a_sample_info as a')
                          ->leftJoin('a_contract as b', 'a.contract_id', '=', 'b.id')
                          ->leftJoin('a_contract_gaiyao as c', 'a.contract_gaiyao_id', '=', 'c.id')
                          ->where([['a.res', '=', 1], ['a.notice', '=', 1]])
                          ->where(function($query) use ($date) {
                              $query->whereNull('a.notice_last_date')->orWhere('a.notice_last_date', '<', $date);
                          })
                          ->whereNotIn('c.tool_id', array_keys($this->noticeData))
                          ->whereIn('a.next_time', $noticeDate)
                          ->whereIn('b.client_name', $client_names)
                          ->update(['a.notice_last_date' => $date]);
                    }else{
                        DB::table('a_sample_info as a')
                          ->leftJoin('a_contract as b', 'a.contract_id', '=', 'b.id')
                          ->leftJoin('a_contract_gaiyao as c', 'a.contract_gaiyao_id', '=', 'c.id')
                          ->where([['a.res', '=', 1], ['a.notice', '=', 1]])
                          ->where(function($query) use ($date) {
                              $query->whereNull('a.notice_last_date')->orWhere('a.notice_last_date', '<', $date);
                          })
                          ->where('c.tool_id', $k)
                          ->whereIn('a.next_time', $noticeDate)
                          ->whereIn('b.client_name', $client_names)
                          ->update(['a.notice_last_date' => $date]);
                    }
                }

            }
        }

    }
}
	
